uniform extern float4x4 gWVP;
uniform extern float4x4 gView;
uniform extern texture  gTex;

uniform extern float3   gEyePosW;

uniform extern float    gFrameProgress;

uniform extern float3   gBillboardAxis;

sampler Tex = sampler_state
{
	Texture = <gTex>;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	AddressU  = CLAMP;
    AddressV  = CLAMP;
};

struct VSInput
{
    float4 posL     : POSITION0;
	float2 texc     : TEXCOORD0;
	float2 offset   : TEXCOORD1;
	float3 axis     : TEXCOORD2;
	float4 color    : COLOR0;
	float energy    : TEXCOORD3;
};

struct VSOutput1
{
    float4 posH  : POSITION0;
	float2 texc  : TEXCOORD0;
	float4 color : COLOR0;
};

struct VSInput2
{
    float3 posL      : POSITION0;
	float2 texc0     : TEXCOORD0;
	float2 texc1     : TEXCOORD1;
	float2 offset    : TEXCOORD2;
};

struct VSOutput2
{
    float4 posH  : POSITION0;
	float2 texc0  : TEXCOORD0;
	float2 texc1  : TEXCOORD1;
};


//////
// using size stored in position
//////
float3 RotateBillboardVertex(float3 posL, float3 viewDir)
{
	float3 rightVec = normalize(cross(viewDir, float3(0,1,0)));
    float3 upVec = normalize(cross(rightVec, viewDir));
	
	float width = posL.x;
	float height = posL.z;
	
	posL = float3(0,0,0);
	posL += rightVec * width;
    posL += upVec * height;
    
    return posL;
}

////////
VSOutput1 BillboardVS(VSInput input)
{
	VSOutput1 output = (VSOutput1)0;

	float3 viewDirW = gEyePosW - input.posL;
    float3 rightVec = normalize(cross(viewDirW, float3(0,1,0)));
    float3 upVec = normalize(cross(rightVec, viewDirW));
	
	float3 posW = input.posL;
	
	posW += rightVec * input.offset.x;
    posW += upVec * input.offset.y;
    
    output.posH = mul(float4(posW, 1.0f), gWVP);
	output.texc = input.texc;
	output.color = input.color * input.energy;

    return output;
}

VSOutput1 FadingBillboardVS(VSInput input)
{
	VSOutput1 output = (VSOutput1)0;

	float3 viewDirW = gEyePosW - input.posL;
    float3 rightVec = normalize(cross(viewDirW, float3(0,1,0)));
    float3 upVec = normalize(cross(rightVec, viewDirW));
	
	float3 posW = input.posL;
	
	posW += rightVec * input.offset.x;
    posW += upVec * input.offset.y;
    
    output.posH = mul(float4(posW, 1.0f), gWVP);
	output.texc = input.texc;
	output.color = input.color * input.energy;

    return output;
}

float4 BillboardPS(VSOutput1 input) : COLOR0
{
    return input.color * tex2D(Tex, input.texc);
}
////////

////////
VSOutput1 AxisAlignedBillboardVS(VSInput input)
{
	VSOutput1 output = (VSOutput1)0;

    float3 viewDir = gEyePosW - input.posL;
    float3 axis = normalize(input.axis);
    
    float3 rightVec = normalize(cross(viewDir, axis));
	
	float width = input.offset.x;
	float height = input.offset.y;
	
	float3 posL = input.posL;
	posL += rightVec * width;
    posL += axis * height;
    
    
    output.posH = mul(float4(posL, 1.0f), gWVP);
	output.texc = input.texc;
	output.color = input.color;

    return output;
}
float4 AxisAlignedBillboardPS(VSOutput1 input) : COLOR0
{
    return input.color * tex2D(Tex, input.texc);
}
////////

////////
VSOutput2 BillboardAnimatedVS(VSInput2 input)
{
	VSOutput2 output = (VSOutput2)0;
	
	
	float3 viewDirW = gEyePosW - input.posL;
    float3 rightVec = normalize(cross(viewDirW, float3(0,1,0)));
    float3 upVec = normalize(cross(rightVec, viewDirW));
	
	float3 posW = input.posL;
	
	posW += rightVec * input.offset.x;
    posW += upVec * input.offset.y;
    
    output.posH = mul(float4(posW, 1.0f), gWVP);

	output.texc0 = input.texc0;
	output.texc1 = input.texc1;

    return output;
}
float4 BillboardAnimatedPS(VSOutput2 input) : COLOR0
{
    return tex2D(Tex, input.texc0) * (1 - gFrameProgress) + tex2D(Tex, input.texc1) * gFrameProgress;
}
////////



technique BillboardAdditiveBlending
{
    pass P0
    {
        AlphaBlendEnable = true;
        SrcBlend = One;
        DestBlend = One;
		ZWriteEnable = false;

        VertexShader = compile vs_1_1 BillboardVS();
        PixelShader = compile ps_1_1 BillboardPS();
    }
}

technique BillboardReplaceBlending
{
    pass P0
    {
        AlphaBlendEnable = true;
        SrcBlend = SrcAlpha;
        DestBlend = InvSrcAlpha;
		ZWriteEnable = false;

        VertexShader = compile vs_1_1 BillboardVS();
        PixelShader = compile ps_1_1 BillboardPS();
    }
}

technique FadingBillboard
{
    pass P0
    {
        AlphaBlendEnable = true;
        SrcBlend = One;
        DestBlend = One;
		ZWriteEnable = false;

        VertexShader = compile vs_1_1 FadingBillboardVS();
        PixelShader = compile ps_1_1 BillboardPS();
    }
}

technique AxisAlignedBillboard
{
    pass P0
    {
        AlphaBlendEnable = true;
        SrcBlend = One;
        DestBlend = One;
		ZWriteEnable = false;

        VertexShader = compile vs_1_1 AxisAlignedBillboardVS();
        PixelShader = compile ps_1_1 AxisAlignedBillboardPS();
    }
}

technique BillboardAnimated
{
    pass P0
    {
        AlphaBlendEnable = true;
        SrcBlend = One;
        DestBlend = One;
		ZWriteEnable = false;

        VertexShader = compile vs_1_1 BillboardAnimatedVS();
        PixelShader = compile ps_1_1 BillboardAnimatedPS();
    }
}
